package com.yupi.yupicturebackend.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yupi.yupicturebackend.constant.UserConstant;
import com.yupi.yupicturebackend.exception.BusinessException;
import com.yupi.yupicturebackend.exception.ErrorCode;
import com.yupi.yupicturebackend.manager.auth.StpKit;
import com.yupi.yupicturebackend.model.dto.user.UserQueryRequest;
import com.yupi.yupicturebackend.model.dto.user.VipCode;
import com.yupi.yupicturebackend.model.entity.User;
import com.yupi.yupicturebackend.model.enums.UserRoleEnum;
import com.yupi.yupicturebackend.model.vo.LoginUserVO;
import com.yupi.yupicturebackend.model.vo.UserVO;
import com.yupi.yupicturebackend.service.UserService;
import com.yupi.yupicturebackend.mapper.UserMapper;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/**
 * @author 李鱼皮
 * @description 针对表【user(用户)】的数据库操作Service实现
 * @createDate 2024-12-09 20:03:03
 * 
 * 重构说明：
 * 本类经过函数式编程重构，大幅减少if语句的使用，主要采用以下技术：
 * 1. Optional类 - 替代null检查和异常处理
 * 2. Stream API - 替代循环和条件判断
 * 3. 函数式接口 - 使用Supplier、Predicate等
 * 4. 链式调用 - 使用Optional.map().filter().orElse()等
 * 5. 延迟执行 - 使用Supplier包装条件判断
 * 6. 方法提取 - 将复杂逻辑拆分为小函数
 * 
 * 重构效果：
 * - 代码更加声明式，减少命令式编程
 * - 提高代码可读性和维护性
 * - 减少嵌套if语句，降低代码复杂度
 * - 增强异常处理的优雅性
 */
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
        implements UserService {

    // 参数校验工具方法 - 使用函数式编程替代if语句
    private void validateParam(boolean condition, String message) {
        Optional.of(condition)
                .filter(valid -> !valid)
                .ifPresent(ignored -> {
                    throw new BusinessException(ErrorCode.PARAMS_ERROR, message);
                });
    }

    // 参数校验工具方法 - 使用Supplier延迟执行
    private void validateParam(Supplier<Boolean> conditionSupplier, String message) {
        Optional.of(conditionSupplier)
                .map(Supplier::get)
                .filter(valid -> !valid)
                .ifPresent(ignored -> {
                    throw new BusinessException(ErrorCode.PARAMS_ERROR, message);
                });
    }

    // 安全执行方法 - 使用Optional包装可能失败的操作
    private <T> T safeExecute(Supplier<T> supplier, String errorMessage) {
        return Optional.of(supplier)
                .map(Supplier::get)
                .orElseThrow(() -> new BusinessException(ErrorCode.SYSTEM_ERROR, errorMessage));
    }

    /**
     * 用户注册
     *
     * @param userAccount   用户账户
     * @param userPassword  用户密码
     * @param checkPassword 校验密码
     * @return
     */
    @Override
    public long userRegister(String userAccount, String userPassword, String checkPassword) {
        // 1. 参数校验 - 使用函数式编程替代if语句
        validateParam(() -> !StrUtil.hasBlank(userAccount, userPassword, checkPassword), "参数为空");
        validateParam(() -> userAccount.length() >= 4, "用户账号过短");
        validateParam(() -> userPassword.length() >= 8 && checkPassword.length() >= 8, "用户密码过短");
        validateParam(() -> userPassword.equals(checkPassword), "两次输入的密码不一致");
        
        // 2. 检查用户账号是否和数据库中已有的重复 - 使用Stream API
        long count = Optional.ofNullable(userAccount)
                .map(account -> {
                    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
                    queryWrapper.eq("userAccount", account);
                    return this.baseMapper.selectCount(queryWrapper);
                })
                .orElse(0L);
        
        validateParam(count == 0, "账号重复");
        
        // 3. 密码加密
        String encryptPassword = getEncryptPassword(userPassword);
        
        // 4. 创建并保存用户 - 使用Builder模式思想
        User user = createUserWithDefaults(userAccount, encryptPassword);
        
        return Optional.of(user)
                .map(this::save)
                .map(success -> success ? user.getId() : null)
                .orElseThrow(() -> new BusinessException(ErrorCode.SYSTEM_ERROR, "注册失败，数据库错误"));
    }

    @Override
    public LoginUserVO userLogin(String userAccount, String userPassword, HttpServletRequest request) {
        // 1. 参数校验 - 使用Supplier延迟执行
        validateParam(() -> !StrUtil.hasBlank(userAccount, userPassword), "参数为空");
        validateParam(() -> userAccount.length() >= 4, "用户账号错误");
        validateParam(() -> userPassword.length() >= 8, "用户密码错误");
        
        // 2. 密码加密
        String encryptPassword = getEncryptPassword(userPassword);
        
        // 3. 查询用户 - 使用Optional替代null检查
        User user = findUserByCredentials(userAccount, encryptPassword);
        
        // 4. 保存登录态
        setupUserSession(user, request);
        
        return getLoginUserVO(user);
    }

    /**
     * 获取加密后的密码
     *
     * @param userPassword 用户密码
     * @return 加密后的密码
     */
    @Override
    public String getEncryptPassword(String userPassword) {
        final String SALT = "yupi";
        return DigestUtils.md5DigestAsHex((SALT + userPassword).getBytes());
    }

    @Override
    public User getLoginUser(HttpServletRequest request) {
        // 使用Optional链式调用替代if语句
        return Optional.ofNullable(request.getSession().getAttribute(UserConstant.USER_LOGIN_STATE))
                .map(userObj -> (User) userObj)
                .filter(currentUser -> currentUser.getId() != null)
                .map(currentUser -> this.getById(currentUser.getId()))
                .orElseThrow(() -> new BusinessException(ErrorCode.NOT_LOGIN_ERROR));
    }

    /**
     * 获取脱敏类的用户信息
     *
     * @param user 用户
     * @return 脱敏后的用户信息
     */
    @Override
    public LoginUserVO getLoginUserVO(User user) {
        return Optional.ofNullable(user)
                .map(this::createLoginUserVO)
                .orElse(null);
    }

    /**
     * 获得脱敏后的用户信息
     *
     * @param user
     * @return
     */
    @Override
    public UserVO getUserVO(User user) {
        return Optional.ofNullable(user)
                .map(this::createUserVO)
                .orElse(null);
    }

    /**
     * 获取脱敏后的用户列表
     *
     * @param userList
     * @return
     */
    @Override
    public List<UserVO> getUserVOList(List<User> userList) {
        return Optional.ofNullable(userList)
                .filter(list -> !CollUtil.isEmpty(list))
                .map(list -> list.stream()
                        .map(this::getUserVO)
                        .collect(Collectors.toList()))
                .orElse(new ArrayList<>());
    }

    @Override
    public boolean userLogout(HttpServletRequest request) {
        // 使用Optional检查登录状态
        return Optional.ofNullable(request.getSession().getAttribute(UserConstant.USER_LOGIN_STATE))
                .map(userObj -> {
                    request.getSession().removeAttribute(UserConstant.USER_LOGIN_STATE);
                    return true;
                })
                .orElseThrow(() -> new BusinessException(ErrorCode.OPERATION_ERROR, "未登录"));
    }

    @Override
    public QueryWrapper<User> getQueryWrapper(UserQueryRequest userQueryRequest) {
        // 使用Optional替代null检查
        return Optional.ofNullable(userQueryRequest)
                .map(this::buildQueryWrapper)
                .orElseThrow(() -> new BusinessException(ErrorCode.PARAMS_ERROR, "请求参数为空"));
    }

    @Override
    public boolean isAdmin(User user) {
        return Optional.ofNullable(user)
                .map(User::getUserRole)
                .map(role -> UserRoleEnum.ADMIN.getValue().equals(role))
                .orElse(false);
    }

    // region ------- 以下代码为用户兑换会员功能 --------

    // 新增依赖注入
    @Autowired
    private ResourceLoader resourceLoader;

    // 文件读写锁（确保并发安全）
    private final ReentrantLock fileLock = new ReentrantLock();

    // VIP 角色常量（根据你的需求自定义）
    private static final String VIP_ROLE = "vip";

    /**
     * 兑换会员
     *
     * @param user
     * @param vipCode
     * @return
     */
    @Override
    public boolean exchangeVip(User user, String vipCode) {
        // 使用Optional进行参数校验和链式处理
        return Optional.ofNullable(user)
                .filter(u -> StrUtil.isNotBlank(vipCode))
                .map(u -> {
                    VipCode targetCode = validateAndMarkVipCode(vipCode);
                    updateUserVipInfo(u, targetCode.getCode());
                    return true;
                })
                .orElseThrow(() -> new BusinessException(ErrorCode.PARAMS_ERROR));
    }

    /**
     * 校验兑换码并标记为已使用
     */
    private VipCode validateAndMarkVipCode(String vipCode) {
        return Optional.of(fileLock)
                .map(lock -> {
                    lock.lock();
                    try {
                        return processVipCodeValidation(vipCode);
                    } finally {
                        lock.unlock();
                    }
                })
                .orElseThrow(() -> new BusinessException(ErrorCode.SYSTEM_ERROR, "系统繁忙"));
    }

    /**
     * 处理VIP码验证逻辑 - 使用Stream API和Optional
     */
    private VipCode processVipCodeValidation(String vipCode) {
        return Optional.of(readVipCodeFile())
                .map(jsonArray -> JSONUtil.toList(jsonArray, VipCode.class))
                .map(codes -> codes.stream()
                        .filter(code -> code.getCode().equals(vipCode) && !code.isHasUsed())
                        .findFirst()
                        .map(target -> {
                            target.setHasUsed(true);
                            writeVipCodeFile(JSONUtil.parseArray(codes));
                            return target;
                        })
                        .orElseThrow(() -> new BusinessException(ErrorCode.PARAMS_ERROR, "无效的兑换码")))
                .orElseThrow(() -> new BusinessException(ErrorCode.SYSTEM_ERROR, "系统繁忙"));
    }

    /**
     * 读取兑换码文件 - 使用Optional包装IO操作
     */
    private JSONArray readVipCodeFile() {
        return Optional.of(resourceLoader)
                .map(loader -> loader.getResource("classpath:biz/vipCode.json"))
                .map(resource -> {
                    try {
                        String content = FileUtil.readString(resource.getFile(), StandardCharsets.UTF_8);
                        return JSONUtil.parseArray(content);
                    } catch (IOException e) {
                        log.error("读取兑换码文件失败", e);
                        throw new BusinessException(ErrorCode.SYSTEM_ERROR, "系统繁忙");
                    }
                })
                .orElseThrow(() -> new BusinessException(ErrorCode.SYSTEM_ERROR, "系统繁忙"));
    }

    /**
     * 写入兑换码文件 - 使用Optional包装IO操作
     */
    private void writeVipCodeFile(JSONArray jsonArray) {
        Optional.of(resourceLoader)
                .map(loader -> loader.getResource("classpath:biz/vipCode.json"))
                .ifPresent(resource -> {
                    try {
                        FileUtil.writeString(jsonArray.toStringPretty(), resource.getFile(), StandardCharsets.UTF_8);
                    } catch (IOException e) {
                        log.error("更新兑换码文件失败", e);
                        throw new BusinessException(ErrorCode.SYSTEM_ERROR, "系统繁忙");
                    }
                });
    }

    /**
     * 更新用户会员信息 - 使用Optional链式调用
     */
    private void updateUserVipInfo(User user, String usedVipCode) {
        Date expireTime = DateUtil.offsetMonth(new Date(), 12);
        
        Optional.of(user)
                .map(u -> createVipUser(u.getId(), expireTime, usedVipCode))
                .map(this::updateById)
                .filter(success -> success)
                .orElseThrow(() -> new BusinessException(ErrorCode.OPERATION_ERROR, "开通会员失败，操作数据库失败"));
    }

    // endregion ------- 以下代码为用户兑换会员功能 --------

    // 辅助方法 - 创建默认用户
    private User createUserWithDefaults(String userAccount, String encryptPassword) {
        User user = new User();
        user.setUserAccount(userAccount);
        user.setUserPassword(encryptPassword);
        user.setUserName("无名");
        user.setUserRole(UserRoleEnum.USER.getValue());
        return user;
    }

    // 辅助方法 - 根据凭据查找用户
    private User findUserByCredentials(String userAccount, String encryptPassword) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("userAccount", userAccount);
        queryWrapper.eq("userPassword", encryptPassword);
        
        return Optional.ofNullable(this.baseMapper.selectOne(queryWrapper))
                .orElseThrow(() -> {
                    log.info("user login failed, userAccount cannot match userPassword");
                    return new BusinessException(ErrorCode.PARAMS_ERROR, "用户不存在或者密码错误");
                });
    }

    // 辅助方法 - 设置用户会话
    private void setupUserSession(User user, HttpServletRequest request) {
        request.getSession().setAttribute(UserConstant.USER_LOGIN_STATE, user);
        StpKit.SPACE.login(user.getId());
        StpKit.SPACE.getSession().set(UserConstant.USER_LOGIN_STATE, user);
    }

    // 辅助方法 - 创建登录用户VO
    private LoginUserVO createLoginUserVO(User user) {
        LoginUserVO loginUserVO = new LoginUserVO();
        BeanUtil.copyProperties(user, loginUserVO);
        return loginUserVO;
    }

    // 辅助方法 - 创建用户VO
    private UserVO createUserVO(User user) {
        UserVO userVO = new UserVO();
        BeanUtil.copyProperties(user, userVO);
        return userVO;
    }

    // 辅助方法 - 构建查询包装器
    private QueryWrapper<User> buildQueryWrapper(UserQueryRequest userQueryRequest) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        
        Optional.ofNullable(userQueryRequest.getId())
                .ifPresent(id -> queryWrapper.eq("id", id));
        
        Optional.ofNullable(userQueryRequest.getUserRole())
                .filter(StrUtil::isNotBlank)
                .ifPresent(role -> queryWrapper.eq("userRole", role));
        
        Optional.ofNullable(userQueryRequest.getUserAccount())
                .filter(StrUtil::isNotBlank)
                .ifPresent(account -> queryWrapper.like("userAccount", account));
        
        Optional.ofNullable(userQueryRequest.getUserName())
                .filter(StrUtil::isNotBlank)
                .ifPresent(name -> queryWrapper.like("userName", name));
        
        Optional.ofNullable(userQueryRequest.getUserProfile())
                .filter(StrUtil::isNotBlank)
                .ifPresent(profile -> queryWrapper.like("userProfile", profile));
        
        Optional.ofNullable(userQueryRequest.getSortField())
                .filter(StrUtil::isNotEmpty)
                .ifPresent(sortField -> {
                    boolean isAscend = "ascend".equals(userQueryRequest.getSortOrder());
                    queryWrapper.orderBy(true, isAscend, sortField);
                });
        
        return queryWrapper;
    }

    // 辅助方法 - 创建VIP用户
    private User createVipUser(Long userId, Date expireTime, String usedVipCode) {
        User updateUser = new User();
        updateUser.setId(userId);
        updateUser.setVipExpireTime(expireTime);
        updateUser.setVipCode(usedVipCode);
        updateUser.setUserRole(VIP_ROLE);
        return updateUser;
    }
}




